#include "../Loaders/ObjLoader.h"
#include "../Core/ResourceManager.h"
#include "../Debug/Exceptions.h"
#include <string>
#include <fstream>

using namespace std;

namespace epix {

ObjLoader::ObjLoader()
{
}

ObjLoader::~ObjLoader()
{
}

Model *ObjLoader::loadFromFile(const char *filename)
{
    ResourceManager *rsmgr = ResourceManager::instance();
    Model *model = rsmgr->get<Model>(filename);
    if(!model)
    {
        _nbV = _nbVt = _nbVn = _nbI = 0;
        _indiceObj = _finalIndex = NULL;
        _posObj = _texObj = _norObj = _pos = _tex = _nor = NULL;

        try
        {
            count(filename);

            int cpt = 1, d = 0;

            _posObj = new float[_nbV];
            if(_nbVt)
            {
                _texObj = new float[_nbVt];
                cpt++;
            }
            if(_nbVn)
            {
                _norObj = new float[_nbVn];
                cpt++;
            }

            d = _nbI/cpt;

            _indiceObj = new unsigned int[_nbI];
            _finalIndex = new unsigned int[d];

            _pos = new float[d*3];
            if(_nbVt) _tex = new float[d*2];
            if(_nbVn) _nor = new float[d*3];

            fill(filename);

            unsigned int index = 0;
            for(unsigned int i=0; i<_nbI;)
            {
                _finalIndex[index] = index;

                _pos[index*3] = _posObj[(_indiceObj[i]-1)*3];
                _pos[index*3+1] = _posObj[(_indiceObj[i]-1)*3+1];
                _pos[index*3+2] = _posObj[(_indiceObj[i]-1)*3+2];
                i++;
                if(_nbVt)
                {
                    _tex[index*2] = _texObj[(_indiceObj[i]-1)*2];
                    _tex[index*2+1] = _texObj[(_indiceObj[i]-1)*2+1];
                    i++;
                }
                if(_nbVn)
                {
                    _nor[index*3] = _norObj[(_indiceObj[i]-1)*3];
                    _nor[index*3+1] = _norObj[(_indiceObj[i]-1)*3+1];
                    _nor[index*3+2] = _norObj[(_indiceObj[i]-1)*3+2];
                    i++;
                }
                index++;
            }

            if(_posObj) delete[] _posObj;
            if(_texObj) delete[] _texObj;
            if(_norObj) delete[] _norObj;
            if(_indiceObj) delete[] _indiceObj;

            model = new Model(filename, d*3, _pos, d*2, _tex, d*3, _nor, d, _finalIndex);
        }
        catch(const exception &e)
        {
            Logger::log() << e.what() << "\n";
            model = NULL;
        }
    }
    return model;
}

void ObjLoader::count(const char *filename)
{
    _nbV = _nbVt = _nbVn = _nbI = 0;
    ifstream file(filename, ios::in);
    if(file)
    {
        string key;
        file >> key;
        while(!file.eof())
        {
            if(key == "v")
                _nbV+=3;
            else if(key == "vt")
                _nbVt+=2;
            else if(key == "vn")
                _nbVn+=3;
            else if(key == "f")
            {
                if(_nbV) _nbI+=3;
                if(_nbVt) _nbI+=3;
                if(_nbVn) _nbI+=3;
            }
            file >> key;
        }
        file.close();
    }
    else
        throw LoadingFailed(filename, "Couldn't open file.");
}

void ObjLoader::fill(const char *filename)
{
    char s;
    ifstream file(filename, ios::in);
    if(file)
    {
        _nbV = _nbVt = _nbVn = _nbI = 0;
        string key;
        file >> key;
        while(!file.eof())
        {
            if(key == "v")
            {
                file >> _posObj[_nbV] >> _posObj[_nbV+1] >> _posObj[_nbV+2];
                _nbV+=3;
            }
            else if(key == "vt")
            {
                file >> _texObj[_nbVt] >> _texObj[_nbVt+1];
                _nbVt+=2;
            }
            else if(key == "vn")
            {
                file >> _norObj[_nbVn] >> _norObj[_nbVn+1] >> _norObj[_nbVn+2];
                _nbVn+=3;
            }
            else if(key == "f")
            {
                for(int i=0; i<3; i++)
                {
                    file >> _indiceObj[_nbI];
                    _nbI++;
                    if(_tex)
                    {
                        file.get(s);
                        file >> _indiceObj[_nbI];
                        _nbI++;
                    }
                    if(_nor)
                    {
                        file.get(s);
                        if(!_tex) file.get(s);
                        file >> _indiceObj[_nbI];
                        _nbI++;
                    }
                }
            }
            file >> key;
        }
        file.close();
    }
    else
        throw LoadingFailed(filename, "Couldn't open file.");
}

}
